from django.shortcuts import render
from QQLoginTool.QQtool import OAuthQQ
from rest_framework import status
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework.views import APIView
from django.conf import settings
from rest_framework_jwt.settings import api_settings

from oauth.serializers import QQAuthUserSerializer
from oauth.utils import generate_save_user_token
from .models import OAuthQQUser
from carts.utils import merge_cart_cookie_to_redis


class QQAuthURLView(APIView):
    """提供QQ登录页面网址
    １、请求方法：get
    ２、url：/oauth/qq/authorization/?next=xxx
    ３、获取参数next
    4、返回数据：login_url
    """

    def get(self, request):
        # 获取next的值，登陆成功后跳转的地址
        next = request.query_params.get('next')
        if not next:
            next = '/'
        # 初始化OAuthQQ对象
        oauth = OAuthQQ(
            client_id=settings.QQ_CLIENT_ID,
            client_secret=settings.QQ_CLIENT_SECRET,
            redirect_uri=settings.QQ_REDIRECT_URI,
            state=next
        )
        # 获取QQ登录扫码页面
        login_url = oauth.get_qq_url()
        # 返回数据
        return Response({'login_url': login_url})


class QQAuthUserView(GenericAPIView):
    """QQ第三方登陆视图"""
    # 指定使用的序列化器
    serializer_class = QQAuthUserSerializer

    def get(self, request):
        """获取QQ openid
        １、获取code，query_params.get
        ２、使用QQ登录SDK，初始化一个OAuthQQ操作对象
        ３、通过code获取到access_token
        ４、通过access_token获取到openid
        ５、根据openid查询数据是否有绑定用户
            １、如果没有绑定用户，则返回openid（使用itsdangerous加密）
            2、如果有绑定用户，则保存状态，生成JWT token，返回数据
        """
        # 获取code
        code = request.query_params.get('code')
        # 判断是否获取到
        if not code:
            return Response({'message': '缺少code授权码'}, status=status.HTTP_400_BAD_REQUEST)
        # 初始化OAuthQQ对象
        oauth = OAuthQQ(
            client_id=settings.QQ_CLIENT_ID,
            client_secret=settings.QQ_CLIENT_SECRET,
            redirect_uri=settings.QQ_REDIRECT_URI,
            state=next
        )
        try:
            # 使用code向QQ服务器请求access_token
            access_token = oauth.get_access_token(code)
            # 使用access_token向QQ服务器请求openid
            openid = oauth.get_open_id(access_token)
        except Exception:
            return Response({'message': 'QQ服务异常'}, status=status.HTTP_503_SERVICE_UNAVAILABLE)
        # 根据openid查询数据库
        try:
            oauth_user = OAuthQQUser.objects.get(openid=openid)
        except OAuthQQUser.DoesNotExist:
            # 如果openid没绑定美多商城用户，创建用户并绑定到openid
            # 返回openid用于绑定时，前端再提交然后和用房id绑定
            return Response({'access_token': generate_save_user_token(openid)})
        else:
            # 如果openid已绑定美多商城用户，直接生成JWT token，并返回
            jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
            # 获取oauth_user关联的user
            user = oauth_user.user
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
            # 构造返回参数
            response = Response({
                'token': token,
                'username': user.username,
                'user_id': user.id
            })
            # 合并购物车
            response = merge_cart_cookie_to_redis(request, user, response)
            return response

    def post(self, request):
        """绑定openid和用户
        获取参数：mobile password sms_code access_token
        返回数据：id username token
        """
        # 获取序列化器对象
        serializer = self.get_serializer(data=request.data)
        # 开启校验
        serializer.is_valid(raise_exception=True)
        # 保存数据
        user = serializer.save()

        # 保存状态
        # 生成JWT token，并响应
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        response = Response({
            'token': token,
            'user_id': user.id,
            'username': user.username
        })
        response = merge_cart_cookie_to_redis(request, user, response)
        return response
